package com.kaifamiao.thyme.servlet;

import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.IContext;
import org.thymeleaf.context.WebContext;
import org.thymeleaf.templatemode.TemplateMode;
import org.thymeleaf.templateresolver.WebApplicationTemplateResolver;
import org.thymeleaf.web.IWebApplication;
import org.thymeleaf.web.IWebExchange;
import org.thymeleaf.web.servlet.JavaxServletWebApplication;
import org.tinylog.Logger;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.charset.Charset;

public class ThymeleafServlet extends HttpServlet {
    private static final String TEMPLATE_ENGINE_KEY = "templateEngine";
    private static final String ENCODING_PARAM_NAME = "encoding";
    private static final String PREFIX_PARAM_NAME = "prefix";
    private static final String SUFFIX_PARAM_NAME = "suffix";
    private static final String DEFAULT_ENCODING = "UTF-8";
    private static final String DEFAULT_PREFIX = "/WEB-INF/templates";
    private static final String DEFAULT_SUFFIX = ".html";

    private String encoding;
    private String prefix;
    private String suffix;
    private TemplateEngine templateEngine;
    private IWebApplication webApplication;

    @Override
    public void init() throws ServletException {
        Logger.trace("初始化`{}`实例", this.getServletName());
        // 获得当前 Web应用对应的 ServletContext 实例
        ServletContext ctx = this.getServletContext();
        // 设定字符编码
        encoding = this.getInitParameter(ENCODING_PARAM_NAME);
        encoding = encoding == null || encoding.trim().isEmpty() ? DEFAULT_ENCODING : encoding;
        encoding = Charset.isSupported(encoding) ? encoding : DEFAULT_ENCODING;
        Logger.trace("模板引擎所使用的字符编码为`{}`", encoding);
        // 设置模板前缀
        prefix = this.getInitParameter(PREFIX_PARAM_NAME);
        prefix = prefix == null || prefix.trim().isEmpty() ? DEFAULT_PREFIX : prefix;
        Logger.trace("模板文件路径前缀为`{}`", prefix);
        // 设置模板后缀
        suffix = this.getInitParameter(SUFFIX_PARAM_NAME);
        suffix = suffix == null || suffix.trim().isEmpty() ? DEFAULT_SUFFIX : suffix;
        Logger.trace("模板文件后缀为`{}`", suffix);
        // 尝试从 ServletContext 实例 中获取 TemplateEngine 实例
        templateEngine = (TemplateEngine) ctx.getAttribute(TEMPLATE_ENGINE_KEY);
        // 若 templateEngine 在 ServletContext 实例中不存在
        if( templateEngine == null ) {
            Logger.trace("创建模板引擎");
            templateEngine = new TemplateEngine();
            webApplication = JavaxServletWebApplication.buildApplication(ctx);
            Logger.trace("创建模板解析器");
            WebApplicationTemplateResolver templateResolver = new WebApplicationTemplateResolver(webApplication);
            templateResolver.setCharacterEncoding("UTF-8");
            templateResolver.setTemplateMode(TemplateMode.HTML);
            templateResolver.setPrefix(prefix);
            templateResolver.setSuffix(suffix);
            // 为 templateEngine 设置 TemplateResolver
            templateEngine.setTemplateResolver(templateResolver);
            // 将 templateEngine 设置到 ServletContext 属性集中
            ctx.setAttribute(TEMPLATE_ENGINE_KEY, templateEngine);
        }

    }

    protected void process(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String contextPath = this.getServletContext().getContextPath();
        Logger.trace("当前应用路径为`{}`", contextPath);
        String uri = req.getRequestURI();
        Logger.trace("当前请求路径为`{}`", uri);
        // 根据 URI 动态确定 模板
        String template = uri.substring(contextPath.length());
        Logger.trace("模板文件为`{}`", template);
        ServletContext app = this.getServletContext();
        resp.setContentType("text/html;charset=" + encoding);
        // 用 JavaxServletWebApplication 中的 buildExchange 创建 IWebExchange 实例
        IWebExchange exchange = ((JavaxServletWebApplication)webApplication).buildExchange(req, resp);
        IContext context = new WebContext(exchange, exchange.getLocale());
        PrintWriter writer = resp.getWriter();
        Logger.trace("解析模板文件并生成HTML文档");
        templateEngine.process( template, context, writer );
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        process(req, resp);
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        process(req, resp);
    }

}
